<template>
  <div>
    <div id="echartsGraph" ref="echartsGraph" class="echarts-graph"></div>
  </div>

</template>

<script>
import graph from '@/assets/json/graph.json'
import { resizeChart } from '@/assets/js/echartOptions.js'

let echarts = require("echarts");
export default {
  name: "EchartsGraph",
  props: {
    nodeAllData: {
      type: Array
    }
  },
  data() {
    return {
      echartsGraph: null,
      options: null,
      baseData: [
        {
          "id": "A",
          "in": ["B", "C", "H"],
          "out": ["D", "E"]
        },
        {
          "id": "B",
          "in": [],
          "out": ["A"]
        },
        {
          "id": "C",
          "in": [],
          "out": ["A"]
        },
        {
          "id": "D",
          "in": ["A"],
          "out": ["F"]
        },
        {
          "id": "E",
          "in": ["A"],
          "out": ["F"]
        },
        {
          "id": "F",
          "in": ["E", "D", "G"],
          "out": []
        },
        {
          "id": "G",
          "in": [],
          "out": ["F"]
        },
        {
          "id": "H",
          "in": ["G", "A"],
          "out": []
        }
      ], //全部节点数据以及数据关系
      nodesData: [], //页面上节点数据
      pageData: [], // 页面上节点关系机构是id，,in，out,expandStatus(展开状态 ture 展开，false 收缩)
      echartsData: [], // 当前echarts的节点数据
      echartsLinks: [],// 当前echarts的关系数据
      currentOnFoceNode: {} //当前点击的节点id
    }
  },
  watch: {
    nodeAllData(val) {

      this.baseData = val
      this.echartsGraph = null
      this.options = null
      this.nodesData = [] //页面上节点数据
      this.pageData = [] // 页面上节点关系机构是id，,in，out,expandStatus(展开状态 ture 展开，false 收缩)
      this.echartsData = [] // 当前echarts的节点数据
      this.echartsLinks = [] // 当前echarts的关系数据
      this.currentOnFoceNode = {}
      if (this.baseData.length > 0) {
        this.appNodeToPage(this.baseData[0].id)
      }
    }
  },
  mounted() {


    // this.appNodeToPage("1")
    // this.appNodeToPage("5")
    // this.appNodeToPage("8")
    const myChart = this.$echarts.init(document.getElementById('echartsGraph'));
    myChart.on('click', (params) => {
      this.nodeClick(params.data.id)
    })

  },
  methods: {
    //从baseData中获取获取数据，模拟从接口中获取数据
    //如果真的在请求接口，这个数据最好缓存下来，要不然每次都会重复请求接口，调用量很大
    getNodeFromBaseData(id) {
      let findResult = this.baseData.filter(item => item.id == id)[0];
      if (findResult) {
        console.log("找到了结果" + findResult);
      } else {
        console.log("未找到相关数据")
      }
      return findResult
      //return this.baseData.filter(item => item.id == id)[0];
    },

    nodeClick(id) {
      //点击的时候进行设置当前节点：
      //如果上次节点和当前点击是同一个节点，只需要进行逆向就行了
      if (this.currentOnFoceNode.nodeId == id) {
        if (this.currentOnFoceNode.expandStatus) {
          this.currentOnFoceNode.expandStatus = true;
        } else {
          this.currentOnFoceNode.expandStatus = false;
        }
      } else {
        //如果上次点击不是和当前点击不是同一个节点，则去pageData中去寻找
        this.currentOnFoceNode.nodeId = id
        this.pageData.forEach(item => {
          if (item.id == id) {
            if (item.expandStatus) {
              this.currentOnFoceNode.expandStatus = true
            } else {
              //当前节点是收缩的，点击之后去点开
              this.currentOnFoceNode.expandStatus = false;
            }
          }
        })
      }

      if (this.currentOnFoceNode.expandStatus) {
        this.remodeNodeFromPage(id)
      } else {
        this.appNodeToPage(id)
      }
    },

    //点击id决定当前页面应该有多少数据
    appNodeToPage(id) {
      this.currentOnFoceNode = { nodeId: id, expandStatus: true }
      let dbNode = this.getNodeFromBaseData(id);
      this.nodesData.push(dbNode.id);
      dbNode.in && dbNode.in.forEach(innodeId => {
        this.nodesData.push(innodeId);
      })
      dbNode.out && dbNode.out.forEach(outnodeId => {
        this.nodesData.push(outnodeId);
      })
      this.doExecute();
    },
    //删除id
    remodeNodeFromPage(id) {
      let currentId = id;
      this.currentOnFoceNode = { nodeId: currentId, expandStatus: false }
      //递归删除我指向的节点
      this.recursionRemoveNodeOut(id)
      //检查还有没有指向我的，如果没有指向我的节点，那这时候的节点应该就是个孤儿节点，然后把除此之外的节点删除掉
      this.checkOrphanNodes(id)
      this.doExecute();
    },

    //用递归的形式去删除掉所有我指向的节点
    recursionRemoveNodeOut(id) {
      let dbNode = this.getNodeFromBaseData(id);
      if (dbNode.out) {
        let myOutNodes = dbNode.out;
        //递归跳出条件 myOutNodes为空，或者myOutNodes不存在
        if (myOutNodes.length > 0) {
          myOutNodes.forEach(outName => {
            this.nodesData = this.nodesData.filter(item => item !== outName);
            this.recursionRemoveNodeOut(outName);
          })
        }
      } else {
        return;
      }
    },
    //检查孤儿节点
    checkOrphanNodes(id) {
      this.pageData.map(node => {
        if (node.id == id) {
          if (!node.in || node.in.length == 0) {
            this.nodesData = [id]
          }
        }
      })

    },

    //把下面三个方法封装为一个方法
    doExecute() {
      this.nodesData = [...new Set(this.nodesData)]
      this.assemableNodeRelation()
      this.localData2EchartsData(this.pageData)
      this.initEchart(this.echartsData, this.echartsLinks)
    },

    initEchart(data, links) {

      let finalEchartsData = [];
      data.forEach(curId => {
        let n = this.getNodeFromBaseData(curId.name);
        let pageDataItem = this.pageData.filter((item) => item.id === curId.name)[0]
        let dn = { id: n.id, name: n.name, expandStatus: pageDataItem.expandStatus, level: n.level }
        finalEchartsData.push(dn)
      })

      const myChart = this.$echarts.init(document.getElementById('echartsGraph'));
      let option = {
        tooltip: {
          confine: true,
          show: true,
          showContent: true,
          textStyle: {
            color: "#fff",
          },
          backgroundColor: "rgba(3, 15, 46, .8)", //tooltip背景色
          borderColor: "rgba(0,255,211,0.19)", //tooltip边框颜色
          borderWidth: 1,
          extraCssText: 'z-index: 99',
          formatter: '{b}',
        },
        // formatter:this.formatterHover,

        animationDurationUpdate: 1500,
        animationEasingUpdate: 'quinticInOut',
        series: [
          {
            type: 'graph',
            layout: 'force',
            legendHoverLink: true, // 是否启用图例 hover(悬停) 时的联动高亮。
            hoverAnimation: true, // 是否开启鼠标悬停节点的显示动画
            coordinateSystem: null, // 坐标系可选
            xAxisIndex: 0, // x轴坐标 有多种坐标系轴坐标选项
            yAxisIndex: 0, // y轴坐标
            force: { // 力引导图基本配置
              // initLayout: , // 力引导的初始化布局，默认使用xy轴的标点
              repulsion: 500, // 节点之间的斥力因子。支持数组表达斥力范围，值越大斥力越大。
              gravity: 0.01, // 节点受到的向中心的引力因子。该值越大节点越往中心点靠拢。
              edgeLength: 200, // 边的两个节点之间的距离，这个距离也会受 repulsion影响 。值越大则长度越长
              layoutAnimation: true, // 因为力引导布局会在多次迭代后才会稳定，这个参数决定是否显示布局的迭代动画
              // 在浏览器端节点数据较多（>100）的时候不建议关闭，布局过程会造成浏览器假死。
              friction: 0.2,
            },
            scaleLimit: {
              //所属组件的z分层，z值小的图形会被z值大的图形覆盖
              min: 0.5, //最小的缩放值
              max: 9 //最大的缩放值
            },
            edgeSymbol: ['circle', 'arrow'],
            edgeSymbolSize: [4, 10],
            roam: true, // 是否开启鼠标缩放和平移漫游。默认不开启，true 为都开启。如果只想要开启缩放或者平移，可以设置成 'scale' 或者 'move'
            // nodeScaleRatio: 0.6, // 鼠标漫游缩放时节点的相应缩放比例，当设为0时节点不随着鼠标的缩放而缩放
            nodeScaleRatio: 0,
            draggable: true, // 节点是否可拖拽，只在使用力引导布局的时候有用。
            focusNodeAdjacency: false,
            symbol: 'rect',
            // symbol:require('@/assets/images/graph-bg.png'),
            // symbol: `image://${icon}`,
            symbolSize: [100, 40],
            // symbolSize:70,
            // symbolOffset:[15,0],
            // symbolSize:70,
            itemStyle: { // ========图形样式，有 normal 和 emphasis 两个状态。
              // normal 是图形在默认状态下的样式；
              // emphasis 是图形在高亮状态下的样式，比如在鼠标悬浮或者图例联动高亮时。
              normal: { // 默认样式
                label: {
                  show: true,
                  color: '#fff',
                  width: 100,
                  overflow: 'truncate'
                },
                // color:'RGBA(10, 55, 88, 1)',
                color: function (params) {
                  const colors = ['#85a5ff', "#b37feb", "#ff85c0", "#95de64", "#5cdbd3", "#69b1ff", "#ffd666", "#fff566", "#d3f261", "#ff7875", "#ff9c6e",
                    "#ffc069", "#8CD282", "#95F300", "#3B0EFF", "#604BFF", "#00BE74", "#04FDB8", "#4a3ac6", "#604BFF"]
                  return new echarts.graphic.LinearGradient(0,
                    0,
                    0,
                    1, [
                    {
                      offset: 0,
                      color: colors[params.data.level]
                    },
                    {
                      offset: 1,
                      color: 'rgba(27, 54, 72, 0.8)',
                    }

                  ])
                },
                borderType: 'solid', // 图形描边类型，默认为实线，支持 'solid'（实线）, 'dashed'(虚线), 'dotted'（点线）。
                borderWidth: 2, // 图形的描边线宽。为 0 时无描边。
                opacity: 1 // 图形透明度。支持从 0 到 1 的数字，为 0 时不绘制该图形。默认0.5

              },
              emphasis: { // 高亮状态

              }
            },
            data: finalEchartsData,
            // links: [],
            links: this.echartsLinks,
            lineStyle: {
              opacity: 0.9,
              width: 2,
              curveness: 0,
              color: 'RGBA(100, 166, 214, 1)'
            }
          }
        ]
      };
      // 绘制图表
      myChart.setOption(option, true, true);
      resizeChart(myChart)
    },

    //根据页面中的节点数据去全部数据中遍历得到id，in，out数据
    assemableNodeRelation() {
      //这是当前的节点关系数据
      let tempPagaData = [];
      this.nodesData.map(item => {
        let dbNode = this.getNodeFromBaseData(item);
        let newIn = dbNode.in && dbNode.in.filter(i => this.nodesData.includes(i));
        let newOut = dbNode.out && dbNode.out.filter(i => this.nodesData.includes(i));
        let link = { id: item, in: newIn, out: newOut }
        tempPagaData.push(link)
      })
      //判定当前节点状态是展开的还是收缩的，如果没有设置expandStatus，则当前节点是
      // this.currentOnFoceNode = {nodeId:id,expandStatus:true}
      //为了赋值当前节点的状态
      tempPagaData.forEach(node => {
        //如果是当前点击的节点，则按照点击节点的状态
        if (node.id == this.currentOnFoceNode.nodeId) {
          node.expandStatus = this.currentOnFoceNode.expandStatus;
        } else {
          let isUpdate = false;
          //先从上一次的pageData中找，找到了就更新为上一次的结果。
          this.pageData.forEach(prePageData => {
            if (prePageData.id == node.id) {
              isUpdate = true;
              if (prePageData.expandStatus) {
                node.expandStatus = true;
              } else {
                node.expandStatus = false;
              }
            }
          })
          //未找到，则默认为false
          if (!isUpdate) {
            node.expandStatus = false;
          }
        }
      })
      this.pageData = tempPagaData;
    },
    //根据页面中的id，in，out关系得到echarts图需要的data以及links
    localData2EchartsData() {
      let tempLinks = [];
      this.pageData.map((item, index) => {
        this.echartsData.push({ name: item.id })
        item.in.map && item.in.map(j => {
          const obj = {
            target: item.id,
            source: j,
            // lineStyle:{
            //   color:"#999999"
            // }
          }
          tempLinks.push(obj);
        })
        item.out.map && item.out.map(j => {
          const obj = {
            target: j,
            source: item.id,
            // lineStyle:{
            //   color:"#999999"
            // }

          }
          tempLinks.push(obj);
        })
      })
      this.echartsLinks = tempLinks

      this.echartsData = this.nodesData.map(item => {
        return { name: item }
      })
    },
    //鼠标悬停显示展开或者关闭
    formatterHover(params) {
      console.log(params, 'params')
      // return params.data.expandStatus?'关闭':'展开'

    }

  }
}
</script>

<style scoped>
.echarts-graph {
  height: 100%;
  width: 100%;
}
</style>
